
#include "glad/glad.h"
#include "shader.h"
#include <fstream>
#include <GL/glext.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>

Shader::Shader(const std::string& vertexpath, const std::string& fragmentpath)
{
    std::ifstream vsf, fsf;
    std::string vscode, fscode;
    vsf.exceptions(std::ifstream::badbit | std::ifstream::failbit);
    fsf.exceptions(std::ifstream::badbit | std::ifstream::failbit);
    try
    {
        vsf.open(vertexpath);
        fsf.open(fragmentpath);
        std::stringstream vss, fss;
        vss << vsf.rdbuf();
        fss << fsf.rdbuf();
        vsf.close();
        fsf.close();
        vscode = vss.str();
        fscode = fss.str();
    }
    catch(std::ifstream::failure e)
    {

    }
    const char*  szvs = vscode.c_str();
    const char* szfs = fscode.c_str();
    GLuint vs, fs;
    vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &szvs, nullptr);
    glCompileShader(vs);
    checkCompileError(vs, "VERTEX");   
    fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1 , &szfs, nullptr);
    glCompileShader(fs);
    checkCompileError(fs, "FRAGMENT");
    shaderId = glCreateProgram();
    glAttachShader(shaderId, vs);
    glAttachShader(shaderId, fs);
    glLinkProgram(shaderId);
    checkCompileError(shaderId, "PROGRAM");
    glDeleteShader(vs);
    glDeleteShader(fs);
}

Shader::~Shader()
{

}

void Shader::checkCompileError(GLuint shader, std::string type)
{
    GLint ok;
    GLchar buf[512];
    if(type != "PROGRAM")
    {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
        if(!ok)
        {
            glGetShaderInfoLog(shader, sizeof(buf), nullptr, buf);
            std::cout << buf << std::endl;
        }
    }
    else 
    {
        glGetProgramiv(shader, GL_LINK_STATUS, &ok);
        if(!ok)
        {
            glGetProgramInfoLog(shader, sizeof(buf), nullptr, buf);
            std::cout << buf << std::endl;
        }
    }
}


void Shader::use(void)
{
    glUseProgram(shaderId);
}

void Shader::setBool(const std::string& name, bool value) const
{
    glUniform1i(glGetUniformLocation(shaderId, name.c_str()), (int)value);
}

void Shader::setInt(const std::string& name, int value) const
{
    glUniform1i(glGetUniformLocation(shaderId, name.c_str()), value);
}

void Shader::setFloat(const std::string& name, float value) const
{
    glUniform1f(glGetUniformLocation(shaderId, name.c_str()), value);
}

GLuint Shader::Id(void)
{
    return shaderId;
}



